package com.yiren.backstage.communication.services.impl;

import android.content.Context;

import com.yiren.backstage.communication.services.IGearService;
import com.yiren.backstage.config.api.LoadConfigApi;
import com.yiren.backstage.currency.bean.CarStateBean;
import com.yiren.backstage.currency.bean.GyroGearDataBean;
import com.yiren.backstage.currency.constant.SignalGConstant;
import com.yiren.backstage.currency.enums.CarStateValueEnum;
import com.yiren.backstage.currency.utils.StringUtil;

import org.apache.commons.lang.StringUtils;

import java.util.Map;

/**
 * Time:2021/11/24 14:19
 * Author:xiaozan
 * Description:档位解析服务类
 */
public class GearServerImpl implements IGearService {

    private Context context;
    private CarStateBean carState;

    private float[] minX;
    private float[] maxX;
    private float[] minY;
    private float[] maxY;
    private float[] tmpX;
    private float[] tmpY;
    private float steadyX;
    private float steadyY;
    private GyroGearDataBean data;

    private boolean checked1 = true;  //换挡之间需要有空挡
    private boolean checked2 = false; //回空挡时需要经过相应的如档口
    private boolean checked3 = true;  //稳定算法
    private boolean checked4 = true;  //入档时需要保持时间
    private long waiteTime = 200; //入档时需保持的时间200ms
    private String gyroStudyData;

    private int currentGears;
    private int nextGears;
    private long changeTime;

    public GearServerImpl(Context context) {
        this.context = context;
        carState = CarStateBean.getInstance();
        initAngleGears(context);
    }

    public CarStateValueEnum cdbGear() {
        CarStateValueEnum cdbGear = CarStateValueEnum.NEUTRAL_GEAR;
        Map<Integer, float[]> cbdMap = LoadConfigApi.loadDeviceStudyConfig(context).getCdbMap();
        //传动比挡位
        float gl = 0;
        if (carState.getSpeed() > 0) {
            gl = (float) (carState.getRotateSpeed() / carState.getSpeed());
            carState.setGearLevel(gl);
        } else {
            carState.setGearLevel(0);
        }

        if (gl >= cbdMap.get(1)[0] && gl <= cbdMap.get(1)[1]) {
            cdbGear = CarStateValueEnum.ONE_GEAR;
        } else if (gl >= cbdMap.get(2)[0] && gl <= cbdMap.get(2)[1]) {
            cdbGear = CarStateValueEnum.TWO_GEAR;
        } else if (gl >= cbdMap.get(3)[0] && gl <= cbdMap.get(3)[1]) {
            cdbGear = CarStateValueEnum.THREE_GEAR;
        } else if (gl >= cbdMap.get(4)[0] && gl <= cbdMap.get(4)[1]) {
            cdbGear = CarStateValueEnum.FOUR_GEAR;
        } else if (gl >= cbdMap.get(5)[0] && gl <= cbdMap.get(5)[1]) {
            cdbGear = CarStateValueEnum.FIVE_GEAR;
        }
        return cdbGear;
    }


    @Override
    public CarStateValueEnum neutralGear(byte[] value) {
        CarStateValueEnum currentGear;
        if (value[7] == 1) {
            currentGear = CarStateValueEnum.NEUTRAL_GEAR;
        } else {
            boolean cdbCheckGear = LoadConfigApi.loadPracticeCarCheckConfig(context).isCdbCheckGear();
            // 离合踩下，跳过，仍然取上次的档位，直到松开为止。
            if (null != carState.getGear() && carState.getSeparationReunion() == CarStateValueEnum.STEP_ON) {
                if (cdbCheckGear) {
                    if (carState.getGear() == CarStateValueEnum.NEUTRAL_GEAR) {
                        return CarStateValueEnum.UNKNOWN_GEAR;
                    }
                    return carState.getGear();
                } else {
                    // 判断是不是空挡,如果是空挡返回未知挡位,返回未知挡的原因：车辆静止时，空挡检测器返回不是空挡，OBD返回是空挡，并且上次挡位为空挡时，这种情况就有问题，所以加一个未知挡位。主要影响：带挡发车评判
                    if (carState.getGear() == CarStateValueEnum.NEUTRAL_GEAR) {
                        currentGear = CarStateValueEnum.UNKNOWN_GEAR;
                    } else {
                        currentGear = carState.getGear();
                    }
                }
            } else {
                if (cdbCheckGear) {
                    //传动比是空挡就返回上次挡位   上次挡位是空挡返回未知挡
                    CarStateValueEnum cdbGear = cdbGear();
                    if (cdbGear == CarStateValueEnum.NEUTRAL_GEAR) {
                        if (carState.getGear() == CarStateValueEnum.NEUTRAL_GEAR) {
                            return CarStateValueEnum.UNKNOWN_GEAR;
                        }
                        return carState.getGear();
                    }
                    return cdbGear;
                } else {
                    currentGear = carState.getGear();
                }
            }
        }
        return currentGear;
    }

    @Override
    public CarStateValueEnum fullGear(byte[] value) {
        CarStateValueEnum currentGear = CarStateValueEnum.NEUTRAL_GEAR;
        if (value[4] == 1) {
            currentGear = CarStateValueEnum.ONE_GEAR;
        }
        if (value[5] == 1) {
            currentGear = CarStateValueEnum.TWO_GEAR;
        }
        if (value[6] == 1) {
            currentGear = CarStateValueEnum.THREE_GEAR;
        }
        if (value[4] == 1 && value[5] == 1) {
            currentGear = CarStateValueEnum.FOUR_GEAR;
        }
        if (value[4] == 1 && value[6] == 1) {
            currentGear = CarStateValueEnum.FIVE_GEAR;
        }
        try {
            boolean cdbCheckGear = LoadConfigApi.loadPracticeCarCheckConfig(context).isCdbCheckGear();
            if (cdbCheckGear) {
                //全挡检测器是空挡就返回空挡
                if (currentGear == CarStateValueEnum.NEUTRAL_GEAR) {
                    return currentGear;
                } else {
                    if (carState.getSeparationReunion() == CarStateValueEnum.STEP_ON) {
                        //踩离合时取上次挡位
                        if (carState.getGear() == CarStateValueEnum.NEUTRAL_GEAR) {
                            return currentGear;
                        }
                        return carState.getGear();
                    } else {
                        //传动比是空挡就返回上次挡位   上次挡位是空挡返回全挡挡位
                        CarStateValueEnum cdbGear = cdbGear();
                        if (cdbGear == CarStateValueEnum.NEUTRAL_GEAR) {
                            if (carState.getGear() == CarStateValueEnum.NEUTRAL_GEAR) {
                                return currentGear;
                            }
                            return carState.getGear();
                        }
                        return cdbGear;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return currentGear;
    }

    private void initAngleGears(Context context) {
        maxX = new float[6];
        minX = new float[6];
        maxY = new float[6];
        minY = new float[6];
        tmpX = new float[20];
        tmpY = new float[20];
        gyroStudyData = LoadConfigApi.loadDeviceStudyConfig(context).getGyroGearStudy();
        if (gyroStudyData != null && gyroStudyData.length() > 0) {
            String[] list = gyroStudyData.split(",");
            if (list.length != 27) return;
            data = new GyroGearDataBean(context);
            if (data != null) {
                data.reset(StringUtil.getStringFloat(list[0]), StringUtil.getStringFloat(list[1]), StringUtil.getStringFloat(list[2]));
                for (int i = 0; i < 6; i++) {
                    minX[i] = StringUtil.getStringFloat(list[i * 4 + 3]);
                    maxX[i] = StringUtil.getStringFloat(list[i * 4 + 4]);
                    minY[i] = StringUtil.getStringFloat(list[i * 4 + 5]);
                    maxY[i] = StringUtil.getStringFloat(list[i * 4 + 6]);
                }
            }
        }
    }

    @Override
    public CarStateValueEnum getGyroGears(Context context) {
        CarStateValueEnum currentGear = CarStateValueEnum.NEUTRAL_GEAR;
        if (SignalGConstant.isAngleGearsChange || StringUtils.isEmpty(gyroStudyData)) {
            initAngleGears(context);
            SignalGConstant.isAngleGearsChange = false;
        }
        if (data != null) {
            data.getGyroData(context);
            float x = data.getDx();
            float y = data.getDy();
            System.arraycopy(tmpX, 0, tmpX, 1, tmpX.length - 1);
            System.arraycopy(tmpY, 0, tmpY, 1, tmpY.length - 1);
            tmpX[0] = x;
            tmpY[0] = y;
            steady3();
            currentGears = getGears();
            switch (currentGears) {
                case 1:
                    currentGear = CarStateValueEnum.ONE_GEAR;
                    break;
                case 2:
                    currentGear = CarStateValueEnum.TWO_GEAR;
                    break;
                case 3:
                    currentGear = CarStateValueEnum.THREE_GEAR;
                    break;
                case 4:
                    currentGear = CarStateValueEnum.FOUR_GEAR;
                    break;
                case 5:
                    currentGear = CarStateValueEnum.FIVE_GEAR;
                    break;
                case 6:
                    currentGear = CarStateValueEnum.REVERSE_GEAR;
                    break;
                default:
                    currentGear = CarStateValueEnum.NEUTRAL_GEAR;
                    break;
            }
            return currentGear;
        }
        return currentGear;
    }

    private int steady1(int gears) {
        if (!checked1) return gears;
        if (gears > 0) {
            boolean posUp1 = (currentGears == 1 || currentGears == 3 || currentGears == 5);
            boolean posUp2 = (gears == 1 || gears == 3 || gears == 5);
            if (gears != currentGears && currentGears != 0 && (posUp1 == posUp2 || gears == 6 || currentGears == 6)) {
                gears = currentGears;
            }
        }
        return gears;
    }

    private int steady2() {
        if (!checked2) return 0;
        float x = steadyX;
        float y = steadyY;
        int gears = 0;
        if (currentGears > 0) {
            if (((currentGears == 1 || currentGears == 2) && !(maxX[0] < x && x < minX[1] && minY[0] < y && y < maxY[1])) ||
                    (currentGears == 3 || currentGears == 4) && !(maxX[2] < x && x < minX[3] && minY[2] < y && y < maxY[3]) ||
                    (currentGears == 5 || currentGears == 6) && !(maxX[4] < x && x < minX[5] && minY[4] < y && y < maxY[5])) {
                gears = currentGears;
            }
            if (gears > 0) {
                int count = 0;
                for (int i = 0; i < 10; i++) {
                    if (maxX[0] < tmpX[i] && tmpX[i] < minX[1] && minY[0] < tmpY[i] && tmpY[i] < maxY[5]) {
                        count++;
                    }
                }
                if (count > 5) {
                    gears = 0;
                }
            }
        }
        return gears;
    }

    private void steady3() {
        if (checked3) {
            float x = 0, y = 0;
            for (int i = 0; i < 5; i++) {
                x += tmpX[i] * (5 - i);
                y += tmpY[i] * (5 - i);
            }
            steadyX = x / (15);
            steadyY = y / (15);
        } else {
            steadyX = tmpX[0];
            steadyY = tmpY[0];
        }
    }

    private int steady4(int gears) {
        if (checked4) {
            if (gears == 0) nextGears = 0;
            if (gears > 0 && currentGears != gears) {
                long time = System.currentTimeMillis();
                if (nextGears != gears) {
                    changeTime = time;
                    nextGears = gears;
                }
                gears = (time - changeTime) >= waiteTime ? gears : 0;
            }
        }
        return gears;
    }

    private int getGears() {
        int gears = steady2();
        float x = steadyX;
        float y = steadyY;
        for (int i = 0; i < 6; i++) {
            if (minX[i] < x && x < maxX[i] && minY[i] < y && y < maxY[i]) {
                gears = i + 1;
                break;
            }
        }
        gears = steady1(gears);
        gears = steady4(gears);
        return gears;
    }


}
